/* wintop.c */

/********************/
/* SPCORE-TOPLEVEL  */
/* for MS-Windows   */
/* (C) 2003 by NAH6 */
/********************/

/*------------*/
/*  INCLUDES  */
/*------------*/

#include <memory.h>
#include <windows.h>
#ifdef _WIN32_WCE
#include <aygshell.h>
#endif
#include "resource.h"

#include "phone.h"
#include "command.h"
#include "wintop.h"

#include "libcodec.h"
extern unsigned char hayescommand[128];
extern unsigned char hayesevent  [128];
extern unsigned short jitter;
/*--------------*/
/*  PROTOTYPES  */
/*--------------*/

static LRESULT CALLBACK wintop_winproc  (HWND wnd, UINT msg, \
                                         WPARAM par1, LPARAM par2);
static void             wintop__scroll  (HWND wnd, int hv, WPARAM par1);
static void             wintop__invalid (HWND wnd, unsigned char x, \
                                         unsigned char y, unsigned char len);
static void             wintop_paint    (HWND wnd, HDC hdc, RECT *rect);
static void             wintop__winwr   (HDC hdc,                             \
                                         unsigned char ox, unsigned char oy,  \
                                         unsigned char x,  unsigned char y,   \
                                         const TCHAR *txt, unsigned char len, \
                                         unsigned long bg, unsigned long fg);
static void             wintop__pos2dot (RECT *rect,       unsigned char ox,  \
                                         unsigned char oy, unsigned char x,   \
                                         unsigned char y,  unsigned char len);
static void             wintop_query    (TCHAR *txt, unsigned long *color, \
                                         unsigned char item);
static unsigned char    wintop__putnum  (TCHAR **prptr, unsigned long num, \
                                         unsigned char base,               \
                                         unsigned char digits);
static unsigned char    wintop__puts    (TCHAR **prptr, const TCHAR *txt);
static void             wintop__putch   (TCHAR **prptr, TCHAR data);

/*-------------*/
/*  VARIABLEN  */
/*-------------*/

HINSTANCE             wintop_inst;
HWND                  wintop_wnd;
#ifdef _WIN32_WCE
static HWND           wintop_mbi;
static SHACTIVATEINFO wintop_sai;
#endif
static unsigned short wintop_sizex;
static unsigned short wintop_sizey;
static unsigned short wintop_fontx;
static unsigned short wintop_fonty;

static unsigned char  wintop_shutdown;
static unsigned char  wintop_copyphase;
static unsigned char  wintop_showtime;

static HANDLE         wintop_cmdexit;
static HANDLE         wintop_cmdthread;
static DWORD          wintop_cmdthreadid;

/*--------------*/
/*  KONSTANTEN  */
/*--------------*/

/* Window-Names */
static const TCHAR wintop_msg_class[] = TEXT ("SPCORE");
static const TCHAR wintop_msg_title[] = TEXT ("SPcore-Machine");

/* Display-Strings (fixed) */
static const TCHAR wintop_txt_line0[]  = TEXT ("SECURE PHONE / Machine");
static const TCHAR wintop_txt_line2a[] = TEXT ("Software-Version:");
static const TCHAR wintop_txt_line2b[] = TEXT (K_WINTOP_SOFTVERTXT);
static const TCHAR wintop_txt_line3a[] = TEXT ("Protocol-Version:");
static const TCHAR wintop_txt_line3b[] = TEXT (K_WINTOP_PROTVERTXT);
static const TCHAR wintop_txt_line4a[] = TEXT ("(C) Copyright 2003 by");
static const TCHAR wintop_txt_line4b[] = TEXT ("NAH6");
static const TCHAR wintop_txt_line6[] =  TEXT ("Current status:");
static const unsigned char wintop_txt_linetab[K_WINTOP_TXTLINES] =
{ 7 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN, 0,
#ifndef _WIN32_WCE
  13, 13, K_WINTOP_TXTCOPYCOL,
#else
  16, 16, K_WINTOP_TXTCOPYCOL,
#endif
  0, 7 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN
};
static const DWORD wintop_txt_linecolor[K_WINTOP_TXTLINES] =
{
  K_WINTOP_FGCOLOR0, 0,
  K_WINTOP_FGCOLOR1, K_WINTOP_FGCOLOR1, K_WINTOP_FGCOLOR2, 0,
  K_WINTOP_FGCOLOR1
};
static const DWORD wintop_txt_copycolor[4] =
{ K_WINTOP_COCOLOR0, K_WINTOP_COCOLOR1, K_WINTOP_COCOLOR2, K_WINTOP_COCOLOR3 };
static const TCHAR *wintop_txt_line[K_WINTOP_TXTLINES][2] =
{
  { wintop_txt_line0,  NULL },              \
  { NULL,              NULL },              \
  { wintop_txt_line2a, wintop_txt_line2b }, \
  { wintop_txt_line3a, wintop_txt_line3b }, \
  { wintop_txt_line4a, wintop_txt_line4b }, \
  { NULL,              NULL },              \
  { wintop_txt_line6,  NULL }
};

/* Display-Strings (item-names) */
static const TCHAR wintop_txt_item0[]  = TEXT ("State:");
static const TCHAR wintop_txt_item1[]  = TEXT ("Substate:");
static const TCHAR wintop_txt_item3[]  = TEXT ("Phone-Nr:");
static const TCHAR wintop_txt_item4[]  = TEXT ("Baudrate:");
static const TCHAR wintop_txt_item5[]  = TEXT ("Carrier:");
static const TCHAR wintop_txt_item7[]  = TEXT ("Codec:");
static const TCHAR wintop_txt_item8[]  = TEXT ("Crypto:");
static const TCHAR wintop_txt_item10[] = TEXT ("Pipelink:");
static const TCHAR *wintop_txt_item[K_WINTOP_TXTITEMS] =
{
  wintop_txt_item0, wintop_txt_item1, NULL,
  wintop_txt_item3, wintop_txt_item4, wintop_txt_item5, NULL,
  wintop_txt_item7, wintop_txt_item8, NULL,
  wintop_txt_item10
};

/*----*/

/* Error-Messages */
static const TCHAR wintop_err_unicode[] = TEXT ("Unicode-support missing.");
static const TCHAR wintop_err_running[] = TEXT ("Program already running.");
static const TCHAR wintop_err_startup[] = TEXT ("Startup not successful.");
static const TCHAR wintop_err_command[] = TEXT ("Command-link failed.");

/*============================================================================*/
/*             C  P  H  O  N  E   -   T  O  P   -   L  E  V  E  L             */
/*============================================================================*/

/*-----------------*/
/*  WINDOWS-ENTRY  */
/*-----------------*/
                                                               /* Entry-Point */
int APIENTRY WinMain (HINSTANCE inst, HINSTANCE pinst,
#ifndef _WIN32_WCE
                      LPSTR cmdline, int show)
#else
                      LPTSTR cmdline, int show)
#endif
{
#ifndef _WIN32_WCE
  WNDCLASSEX wc;
  HANDLE phnd;
  HICON sicon;
#else
  WNDCLASS wc;
#endif
  HANDLE thnd,elck;
  HCURSOR cursor;
  HBRUSH brush;
  HICON bicon;
  HWND wnd;
  MSG msg;
  DWORD e;
  ATOM a;
  BOOL b;

  /* Adjust priotity */
  thnd = GetCurrentThread ();
#ifndef _WIN32_WCE
  phnd = GetCurrentProcess ();
  SetPriorityClass (phnd, REALTIME_PRIORITY_CLASS);
#endif
  SetThreadPriority (thnd, K_WINTOP_WINPRIO);

  /* Create event-lock */
  elck = CreateEvent (NULL, TRUE, 0, wintop_msg_class);
  if (elck == NULL)
  {
    err_unicode:
    MessageBox (NULL, wintop_err_unicode, wintop_msg_title, \
                MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
    return E_WINTOP_UNICODE;
  }

  /* Check single run */
  e = GetLastError ();
  if (e == ERROR_ALREADY_EXISTS)
  {
    CloseHandle (elck);
    MessageBox (NULL, wintop_err_running, wintop_msg_title, \
                MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
    wnd = FindWindow (wintop_msg_class, NULL);
    if (wnd != NULL)
    {
      ShowWindow (wnd, SW_SHOWNORMAL);
      SetForegroundWindow (wnd);
    }
    return E_WINTOP_RUNNING;
  }

  /* Load data */
  wintop_inst = inst;
  bicon  = LoadIcon (inst, (LPCTSTR)IDI_BIG);
  cursor = LoadCursor (NULL, IDC_ARROW);
  brush  = CreateSolidBrush (K_WINTOP_BGCOLOR0);
#ifndef _WIN32_WCE
  sicon  = LoadIcon (inst, (LPCTSTR)IDI_SMALL);
#endif

  /* Register window-class */
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC)wintop_winproc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = inst;
  wc.hIcon         = bicon;
  wc.hCursor       = cursor;
  wc.hbrBackground = brush;
  wc.lpszClassName = wintop_msg_class;
#ifndef _WIN32_WCE
  wc.cbSize        = sizeof (WNDCLASSEX);
  wc.hIconSm       = sicon;
  wc.lpszMenuName  = (LPCSTR)IDM_MENU;
  a = RegisterClassEx (&wc);
#else
  wc.lpszMenuName  = NULL;
  a = RegisterClass (&wc);
#endif
  if (!a)
  {
    CloseHandle (elck);
    goto err_unicode;
  }

  /* Create main-window */
#ifndef _WIN32_WCE
  wintop_wnd = CreateWindowEx (0, wintop_msg_class, wintop_msg_title, \
               WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0, 0,   \
               CW_USEDEFAULT, CW_USEDEFAULT,                          \
               (HWND)NULL, (HMENU)NULL, inst, NULL);
#else
  wintop_wnd = CreateWindowEx (0, wintop_msg_class, wintop_msg_title, \
               WS_HSCROLL | WS_VSCROLL, 0, 26, 240, 268,              \
               (HWND)NULL, (HMENU)NULL, inst, NULL);
#endif
  if (wintop_wnd == NULL)
  {
    UnregisterClass (wintop_msg_class, wintop_inst);
    CloseHandle (elck);
    MessageBox (NULL, wintop_err_startup, wintop_msg_title, \
                MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
    return E_WINTOP_STARTUP;
  }
  ResumeThread (wintop_cmdthread);
  ShowWindow (wintop_wnd, SW_HIDE);
  UpdateWindow (wintop_wnd);

  /* Message loop */
  while (42)
  {
    b = GetMessage (&msg, NULL, 0, 0);
    if (!b)
      break;
    TranslateMessage (&msg);
    DispatchMessage  (&msg);
  }

  /* Exit program */
  UnregisterClass (wintop_msg_class, wintop_inst);
  CloseHandle (elck);
  if ((!(HIWORD (msg.wParam)) || (HIWORD (msg.wParam)) == 0xFFFF) \
   && (msg.wParam & 0x00008000L) == 0x00008000L)
    MessageBox (NULL, wintop_err_command, wintop_msg_title, \
                MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  return msg.wParam;
}

/*----------------------------------------------------------------------------*/

/*---------------*/
/*  MAIN-WINDOW  */
/*---------------*/
                                                               /* Main-Window */
static LRESULT CALLBACK wintop_winproc (HWND wnd, UINT msg, \
                                        WPARAM par1, LPARAM par2)
{
#ifdef _WIN32_WCE
  SHMENUBARINFO mbi;
  BOOL b;
#endif
  PAINTSTRUCT ps;
  TEXTMETRIC tm;
  SCROLLINFO si;
  HGDIOBJ font;
  LRESULT n;
  DWORD d;
  HDC hdc;

  /* Window-Procedure */
  n = 0;
  switch (msg)
  {
    case WM_CREATE:
      /* Setup Win-Thread */
#ifdef _WIN32_WCE
      memset (&mbi, 0, sizeof (SHMENUBARINFO));
      mbi.cbSize     = sizeof (SHMENUBARINFO);
      mbi.hwndParent = wnd;
      mbi.nToolBarId = IDM_MENU;
      mbi.hInstRes   = wintop_inst;
      mbi.nBmpId     = 0;
      mbi.cBmpImages = 0;
      b = SHCreateMenuBar (&mbi);
      if (!b)
        goto err_exit2;
      wintop_mbi = mbi.hwndMB;
      memset (&wintop_sai, 0, sizeof (SHACTIVATEINFO));
      wintop_sai.cbSize = sizeof (SHACTIVATEINFO);
#endif
      hdc = GetDC (wnd);
      font = GetStockObject (SYSTEM_FONT);
      SelectObject (hdc, font);
      GetTextMetrics (hdc, &tm);
      wintop_fontx = (unsigned short)(tm.tmAveCharWidth);
      wintop_fontx = ((wintop_fontx << 1) + wintop_fontx) >> 1;
      wintop_fonty = (unsigned short)(tm.tmHeight + tm.tmExternalLeading);
      ReleaseDC (wnd, hdc);
      wintop_shutdown  = 0x00;
      wintop_copyphase = 0x00;
      wintop_showtime  = 0x00;
      SetTimer (wnd, 1, K_WINTOP_TIMERTICK, (TIMERPROC)NULL);
      /* Init Phone-Machine */
      phone_install ();
      /* Create Cmd-Thread */
      wintop_cmdexit = CreateEvent (NULL, TRUE, 0, NULL);
      if (wintop_cmdexit == NULL)
        goto err_exit1;
      wintop_cmdthread = CreateThread (NULL, 0, cmd_thread, &wintop_cmdexit, \
                                       CREATE_SUSPENDED, &(wintop_cmdthreadid));
      if (wintop_cmdthread != NULL)
        SetThreadPriority (wintop_cmdthread, K_WINTOP_CMDPRIO);
      else
      {
        CloseHandle (wintop_cmdexit);
        err_exit1:
        phone_remove ();
        KillTimer (wnd, 1);
#ifdef _WIN32_WCE
        CommandBar_Destroy (wintop_mbi);
        err_exit2:
#endif
        n = -1;
      }
      break;
    case WM_CLOSE:
      /* Close Session */
      shutdown:
      wintop_shutdown = 1;
      SetEvent (wintop_cmdexit);
      d = WaitForSingleObject (wintop_cmdthread, 0);
      if (d == WAIT_TIMEOUT)
        break;
      phone_off (0, NULL);
      /*fallthrough*/
    case K_WINTOP_EXITMSG:
      /* Send Destroy-Messages */
      wintop_shutdown = 2;
      DestroyWindow (wnd);
      break;
    case WM_DESTROY:
      /* Destroy Session */
      wintop_shutdown = 3;
      SetEvent (wintop_cmdexit);
      WaitForSingleObject (wintop_cmdthread, INFINITE);
      GetExitCodeThread (wintop_cmdthread, &d);
      CloseHandle (wintop_cmdthread);
      CloseHandle (wintop_cmdexit);
      phone_remove ();
      KillTimer (wnd, 1);
#ifdef _WIN32_WCE
      CommandBar_Destroy (wintop_mbi);
#endif
      PostQuitMessage (d);
      break;
#ifdef _WIN32_WCE
    case WM_SETTINGCHANGE:
      SHHandleWMSettingChange (wnd, par1, par2, &wintop_sai);
      break;
    case WM_ACTIVATE:
      SHHandleWMActivate (wnd, par1, par2, &wintop_sai, FALSE);
      break;
#endif
    case WM_PAINT:
      /* Repaint Screen */
      hdc = BeginPaint (wnd, &ps);
      wintop_paint (wnd, hdc, &(ps.rcPaint));
      EndPaint (wnd, &ps);
      break;
    case WM_SIZE:
      /* New Size */
      wintop_sizex = LOWORD (par2) + 1;
      wintop_sizey = HIWORD (par2) + 1;
      si.cbSize = sizeof (SCROLLINFO);
      si.fMask  = SIF_PAGE | SIF_RANGE;
      si.nMin   = 0;
      si.nMax   = 7 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN;
      si.nPage  = wintop_sizex / wintop_fontx;
      SetScrollInfo (wnd, SB_HORZ, &si, TRUE);
      si.nMax   = 4 + K_WINTOP_TXTLINES + K_WINTOP_TXTITEMS;
      si.nPage  = wintop_sizey / wintop_fonty;
      SetScrollInfo (wnd, SB_VERT, &si, TRUE);
      break;
    case WM_HSCROLL:
      /* Horizontal Scroll */
      hscroll:
      wintop__scroll (wnd, SB_HORZ, par1);
      break;
    case WM_VSCROLL:
      /* Vertical Scroll */
      vscroll:
      wintop__scroll (wnd, SB_VERT, par1);
      break;
    case WM_TIMER:
      /* Timer Jobs */
      if (!wintop_shutdown)            /* Flash Copyright */
        wintop_copyphase++;
      else
        wintop_copyphase--;
      wintop__invalid (wnd, K_WINTOP_TXTCOPYCOL, K_WINTOP_TXTCOPYLINE, \
                       K_WINTOP_TXTCOPYLEN);
      if (wintop_showtime < 255)       /* Minimize Window */
      {
        wintop_showtime++;
        if (wintop_showtime == K_WINTOP_SHOWTIME)
          ShowWindow (wnd, SW_MINIMIZE);
      }
      break;
    case K_WINTOP_UPDATEMSG:
      /* Update Value */
      wintop__invalid (wnd, 5 + K_WINTOP_TXTITEMNLEN,                 \
                       (unsigned char)(3 + K_WINTOP_TXTLINES + par1), \
                       K_WINTOP_TXTITEMDLEN);
      break;
    case WM_KEYDOWN:
      /* Keyboard press */
      switch (par1)
      {
        /* Scroll keys */
        case VK_UP:
          par1 = SB_LINEUP;
          goto vscroll;
        case VK_DOWN:
          par1 = SB_LINEDOWN;
          goto vscroll;
        case VK_PRIOR:
          par1 = SB_PAGEUP;
          goto vscroll;
        case VK_NEXT:
          par1 = SB_PAGEDOWN;
          goto vscroll;
        case VK_HOME:
          par1 = SB_TOP;
          goto vscroll;
        case VK_END:
          par1 = SB_BOTTOM;
          goto vscroll;
        case VK_LEFT:
          par1 = SB_LINELEFT;
          goto hscroll;
        case VK_RIGHT:
          par1 = SB_LINERIGHT;
          goto hscroll;
        /* Command keys */
        case 0x30: /*0*/
          break;
        default:
          goto defproc;
      }
      break;
    case WM_COMMAND:
      /* Menu command */
      switch (LOWORD (par1))
      {
        case IDM_FILE_EXIT:
          goto shutdown;
        case IDM_PHONE_HANGUP:
          break;
        case IDM_PHONE_DIAL:
          break;
        case IDM_PHONE_ANSWER:
          break;
        default:
          goto defproc;
      }
      break;
    default:
      defproc:
      n = DefWindowProc (wnd, msg, par1, par2);
      break;
  }
  return n;
}

/*====*/

static void wintop__scroll (HWND wnd, int hv, WPARAM par1)   /* Scroll Window */
{
  SCROLLINFO si;
  int i,x,y;

  /* Update scrollbar */
  si.cbSize = sizeof (SCROLLINFO);
  si.fMask  = SIF_ALL;
  GetScrollInfo (wnd, hv, &si);
  i = si.nPos;
  switch (LOWORD (par1))
  {
    case SB_LEFT:
      si.nPos = 0;
      break;
    case SB_RIGHT:
      si.nPos = si.nMax;
      break;
    case SB_LINELEFT:
      si.nPos--;
      break;
    case SB_LINERIGHT:
      si.nPos++;
      break;
    case SB_PAGELEFT:
      si.nPos -= si.nPage;
      break;
    case SB_PAGERIGHT:
      si.nPos += si.nPage;
      break;
    case SB_THUMBTRACK:
    case SB_THUMBPOSITION:
      si.nPos = si.nTrackPos;
      break;
    default:
      return;
  }
  si.fMask = SIF_POS;
  SetScrollInfo (wnd, hv, &si, TRUE);

  /* Update window */
  GetScrollInfo (wnd, hv, &si);
  if (i != si.nPos)
  {
    i -= si.nPos;
    x = 0;
    y = 0;
    if (hv == SB_HORZ)
      x = wintop_fontx * i;
    else
      y = wintop_fonty * i;
    ScrollWindowEx (wnd, x, y, NULL, NULL, NULL, NULL, \
                    SW_INVALIDATE | SW_ERASE);
    UpdateWindow (wnd);
  }
}

/*----*/
                                                         /* Invalidate Window */
static void wintop__invalid (HWND wnd, unsigned char x, unsigned char y, \
                             unsigned char len)
{
  unsigned char ox,oy;
  SCROLLINFO si;
  RECT rect;

  /* Calc Area */
  si.cbSize = sizeof (SCROLLINFO);
  si.fMask  = SIF_POS;
  GetScrollInfo (wnd, SB_HORZ, &si);
  ox = (unsigned char)(si.nPos);
  GetScrollInfo (wnd, SB_VERT, &si);
  oy = (unsigned char)(si.nPos);
  wintop__pos2dot (&rect, ox, oy, x, y, len);

  /* Limit Area */
  if ((rect.left >= wintop_sizex) || (rect.right <= 0) \
   || (rect.top  >= wintop_sizey) || (rect.bottom <= 0))
    return;
  if (rect.left < 0)
    rect.left = 0;
  if (rect.right > wintop_sizex)
    rect.right = wintop_sizex;
  if (rect.top < 0)
    rect.top = 0;
  if (rect.bottom > wintop_sizey)
    rect.bottom = wintop_sizey;

  /* Invalidate */
  rect.right--;
  rect.bottom--;
  InvalidateRect (wnd, &rect, FALSE);
}

/*----------------*/
/*  STATUS-PAINT  */
/*----------------*/

static void wintop_paint (HWND wnd, HDC hdc, RECT *rect)    /* Status-Display */
{
  TCHAR txtbuf[K_WINTOP_TXTITEMDLEN+1];
  unsigned char ox,oy,x0,x1,y0,y1,x,y,z;
  unsigned long d;
  const TCHAR *p;
  SCROLLINFO si;
  HGDIOBJ font;
  HBRUSH brush;
  RECT area;

  /* Calc Redraw-Area */
  /* ox,x0,x1 */
  si.cbSize = sizeof (SCROLLINFO);
  si.fMask  = SIF_POS;
  GetScrollInfo (wnd, SB_HORZ, &si);
  ox = (unsigned char)(si.nPos);
  d = (rect->left  / wintop_fontx) + ox;
  if (d >= (7 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN))
    return;
  else if (!d)
    d = 1;
  x0 = (unsigned char)d;
  d = (rect->right / wintop_fontx) + ox;
  if (!d)
    return;
  else if (d >= (7 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN))
    d = 6 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN;
  x1 = (unsigned char)d;
  /* oy,y0,y1 */
  GetScrollInfo (wnd, SB_VERT, &si);
  oy = (unsigned char)(si.nPos);
  d = (rect->top / wintop_fonty) + oy;
  if (d >= (4 + K_WINTOP_TXTLINES + K_WINTOP_TXTITEMS))
    return;
  else if (!d)
    d = 1;
  y0 = (unsigned char)d;
  d = (rect->bottom / wintop_fonty) + oy;
  if (!d)
    return;
  else if (d >= (4 + K_WINTOP_TXTLINES + K_WINTOP_TXTITEMS))
    d = 3 + K_WINTOP_TXTLINES + K_WINTOP_TXTITEMS;
  y1 = (unsigned char)d;

  /* Redraw Screen */
  font = GetStockObject (SYSTEM_FONT);
  SelectObject (hdc, font);
  brush = CreateSolidBrush (K_WINTOP_BGCOLOR1);
  for (y=y0; y<=y1; y++)
  {
    if (y <= K_WINTOP_TXTLINES)
    {
      /* Fixed-Text */
      x = wintop_txt_linetab[y-1];
      d = wintop_txt_linecolor[y-1];
      if (x0 < x)
      {
        p = wintop_txt_line[y-1][0];
        if (p != NULL)
          wintop__winwr (hdc, ox, oy, 1, y, p, (unsigned char)(x - 1), \
                         K_WINTOP_BGCOLOR0, d);
      }
      if (x1 >= x)
      {
        p = wintop_txt_line[y-1][1];
        if (p != NULL)
        {
          if (y != K_WINTOP_TXTCOPYLINE)
            wintop__winwr (hdc, ox, oy, x, y, p, (unsigned char)               \
                         (7 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN - x),\
                          K_WINTOP_BGCOLOR0, d);
          else
          {
            /* Copyright */
            txtbuf[1] = 0;
            for (z=0; z<4; z++)
            {
              d = wintop_txt_copycolor[(z + wintop_copyphase) & 0x03];
              txtbuf[0] = *p++;
              wintop__winwr (hdc, ox, oy, (unsigned char)(x + z), y, txtbuf, \
                             1, K_WINTOP_BGCOLOR0, d);
            }
          }
        }
      }
    }
    else if (y > (1 + K_WINTOP_TXTLINES))
    {
      /* Data-Items */
      if ((x0 < (6 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN)) && (x1 > 1))
      {
        /* Item-Background */
        x = x0;
        if (x < 2)
          x = 2;
        z = x1;
        if (z >= (6 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN))
          z = 5 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN;
        wintop__pos2dot (&area, ox, oy, x, y, (unsigned char)(z - x + 1));
        FillRect (hdc, &area, brush);
      }
      if ((y > (2 + K_WINTOP_TXTLINES)) \
       && (y < (3 + K_WINTOP_TXTLINES + K_WINTOP_TXTITEMS)))
      {
        /* Item-Text */
        p = wintop_txt_item[y-3-K_WINTOP_TXTLINES];
        if (p != NULL)
        {
          if ((x0 < (3 + K_WINTOP_TXTITEMNLEN)) && (x1 > 2))
            wintop__winwr (hdc, ox, oy, 3, y, p, K_WINTOP_TXTITEMNLEN, \
                           K_WINTOP_BGCOLOR1, K_WINTOP_FGCOLOR0);
          if ((x0 < (5 + K_WINTOP_TXTITEMNLEN + K_WINTOP_TXTITEMDLEN)) \
           && (x1 > (4 + K_WINTOP_TXTITEMNLEN)))
          {
            d = K_WINTOP_FGCOLOR0;
            wintop_query (txtbuf, &d, (unsigned char)(y-3-K_WINTOP_TXTLINES));
            wintop__winwr (hdc, ox, oy, 5 + K_WINTOP_TXTITEMNLEN, y, txtbuf, \
                           K_WINTOP_TXTITEMDLEN, K_WINTOP_BGCOLOR1, d);
          }
        }
      }
    }
  }
  DeleteObject (brush);
}

/*====*/
                                                              /* Write String */
static void wintop__winwr (HDC hdc, unsigned char ox, unsigned char oy, \
                           unsigned char x,  unsigned char y,           \
                           const TCHAR *txt, unsigned char len,         \
                           unsigned long bg, unsigned long fg)
{
  RECT rect;
  int n;

  n = lstrlen (txt);
  wintop__pos2dot (&rect, ox, oy, x, y, len);
  SetTextColor (hdc, fg);
  SetBkColor (hdc, bg);
  ExtTextOut (hdc, rect.left, rect.top, ETO_CLIPPED, &rect, txt, n, NULL);
}

/*----*/
                                                              /* Calc Dot-Pos */
static void wintop__pos2dot (RECT *rect, unsigned char ox, unsigned char oy, \
                             unsigned char x, unsigned char y, \
                             unsigned char len)
{
  rect->left   = x;
  rect->left  -= ox;
  rect->right  = rect->left + len;
  rect->left  *= wintop_fontx;
  rect->right *= wintop_fontx;
  rect->top    = y;
  rect->top   -= oy;
  rect->top   *= wintop_fonty;
  rect->bottom = rect->top + wintop_fonty;
}

/*====*/
                                                          /* Query Item-Value */
static void wintop_query (TCHAR *txt, unsigned long *color, unsigned char item)
{
  static unsigned short cnt[K_WINTOP_TXTITEMS];
  const unsigned char *p;

  if (cnt[item] < 0xFFFF)
    cnt[item]++;

  switch (item)
  {
    case K_WINTOP_PARSTATE:
      hayescommand[20] = 0;
      wintop__putch (&txt, 'A');
      wintop__putch (&txt, 'T');
      p = hayescommand;
      while (*p)
        wintop__putch (&txt, *p++);
      break;
    case K_WINTOP_PARSUBSTATE:
      hayesevent[20] = 0;
      p = hayesevent;
      while (*p)
        wintop__putch (&txt, *p++);
      break;
    case K_WINTOP_PARPHONENR:
      wintop__putnum (&txt, jitter, 10, 4);
      break;
    default:
      wintop__putnum (&txt, cnt[item], 16, 4);
      if (item > 2)
        *color = K_WINTOP_FGCOLOR3;
      if (item > 4)
        *color = K_WINTOP_FGCOLOR4;
  }
  wintop__putch (&txt, 0);
}

/*----*/
                                                        /* Print Reply-Number */
static unsigned char wintop__putnum (TCHAR **prptr,      unsigned long num, \
                                     unsigned char base, unsigned char digits)
{
  unsigned char numbuf[32],n,x,y;
  TCHAR c;

  /* Split number */
  for (x=0; x<32; x++)
  {
    if (!num)
      break;
    y = (unsigned char)(num % base);
    num /= base;
    if (y < 10)
      y += 0x30;
    else if (y < 36)
      y += 0x37;
    else
      y = 0x2A;
    numbuf[x] = y;
  }

  /* Print number */
  n = digits;
  if (x > n)
    n = x;
  for (y=n; y>0; y--)
  {
    if (y > x)
      c = 0x30;
    else
      c = numbuf[y-1];
    wintop__putch (prptr, c);
  }
  return n;
}

                                                        /* Print Reply-String */
static unsigned char wintop__puts (TCHAR **prptr, const TCHAR *txt)
{
  unsigned char n;

  /* Print string */
  n = 0;
  while (*txt)
  {
    wintop__putch (prptr, *txt++);
    n++;
  }
  return n;
}


static void wintop__putch (TCHAR **prptr, TCHAR data)     /* Print Reply-Char */
{
  TCHAR *p;

  /* Print character */
  p = *prptr;
  *p++ = data;
  *prptr = p;
}

/*============================================================================*/

/*-----------------*/
/*  UPDATE-NOTIFY  */
/*-----------------*/

void wintop_exit (void)                                  /* Send Exit-Message */
{
  PostMessage (wintop_wnd, K_WINTOP_EXITMSG, 0, 0);
}


void wintop_notify (unsigned char item)            /* Notify Parameter-Change */
{
  PostMessage (wintop_wnd, K_WINTOP_UPDATEMSG, item, 0);
}


/*** EOF ***/
